package com.dinuscxj.progressbar;

import ohos.agp.components.AttrSet;
import ohos.agp.components.Component;
import ohos.agp.render.*;
import ohos.agp.utils.*;
import ohos.app.Context;

import java.lang.annotation.Retention;
import java.lang.annotation.RetentionPolicy;

/**
 * CircleProgressBar继承Component, 是包含实心和线条两种风格的圆环进度条. 此外, 进度值可以随意定制.
 */
public class CircleProgressBar extends Component implements Component.DrawTask, Component.LayoutRefreshedListener {
    /**
     * LINE
     */
    public static final int LINE = 0;
    /**
     * SOLID
     */
    public static final int SOLID = 1;
    /**
     * SOLID_LINE
     */
    public static final int SOLID_LINE = 2;

    /**
     * LINEAR
     */
    public static final int LINEAR = 0;
    /**
     * RADIAL
     */
    public static final int RADIAL = 1;
    /**
     * SWEEP
     */
    public static final int SWEEP = 2;

    private static final int DEFAULT_MAX = 100;
    private static final float MAX_DEGREE = 360.0f;
    private static final float LINEAR_START_DEGREE = 90.0f;

    private static final int DEFAULT_START_DEGREE = -90;

    private static final int DEFAULT_LINE_COUNT = 45;

    private static final float DEFAULT_LINE_WIDTH = 4.0f;
    private static final float DEFAULT_PROGRESS_TEXT_SIZE = 40.0f;
    private static final float DEFAULT_PROGRESS_STROKE_WIDTH = 1.0f;

    private static final int COLOR_FFF2A670 = 0xffaa66cc;
    private static final int COLOR_FFD3D3D5 = 0xffe3e3e5;

    private final RectFloat mProgressRectF = new RectFloat();
    private final RectFloat mBoundsRectF = new RectFloat();
    private Rect mProgressTextRect = new Rect();

    private final Paint mProgressPaint = new Paint();
    private final Paint mProgressBackgroundPaint = new Paint();
    private final Paint mTextBgPaint = new Paint();

    private final Paint mProgressTextPaint = new Paint();

    private float mRadius;
    private float mCenterX;
    private float mCenterY;

    private int mProgress;
    private int mMax = DEFAULT_MAX;

    // Only work well in the Line Style, represents the line count of the rings included
    private int mLineCount;

    // Only work well in the Line Style, Height of the line of the progress bar
    private float mLineWidth;

    // Stroke width of the progress of the progress bar
    private float mProgressStrokeWidth;

    // Text size of the progress of the progress bar
    private float mProgressTextSize;

    // Start color of the progress of the progress bar
    private Color mProgressStartColor;

    // End color of the progress of the progress bar
    private Color mProgressEndColor;

    // Color of the progress value of the progress bar
    private Color mProgressTextColor;

    // Background color of the progress of the progress bar
    private Color mProgressBackgroundColor;

    // the rotate degree of the canvas, default is -90.
    private int mStartDegree;

    // whether draw the background only outside the progress area or not
    private boolean mDrawBackgroundOutsideProgress;

    // Format the current progress value to the specified format
    private ProgressFormatter mProgressFormatter = new DefaultProgressFormatter();

    // The style of the progress color
    @Style
    private int mStyle;

    // The Shader of mProgressPaint
    @ShaderMode
    private int mShader;

    // The Stroke Cap of mProgressPaint and mProgressBackgroundPaint
    private Paint.StrokeCap mCap = Paint.StrokeCap.BUTT_CAP;

    // The blur radius of mProgressPaint
    private int mBlurRadius;

    // The blur style of mProgressPaint
    private MaskFilter.Blur mBlurStyle;

    public CircleProgressBar(Context context) {
        this(context, null);
    }

    public CircleProgressBar(Context context, AttrSet attrs) {
        super(context, attrs);
        initFromAttributes(context, attrs);
        initPaint();
    }

    /**
     * Basic data initialization
     * @param context context
     * @param attrs attrs
     */
    @SuppressWarnings("ResourceType")
    private void initFromAttributes(Context context, AttrSet attrs) {
        if(attrs == null){
            mProgressBackgroundColor =  new Color(COLOR_FFD3D3D5);
            mLineCount =  DEFAULT_LINE_COUNT;
            mStyle = LINE;
            mShader = LINEAR;
            mCap = Paint.StrokeCap.BUTT_CAP;
            mLineWidth =  vpToPx(getContext(), DEFAULT_LINE_WIDTH);
            mProgressTextSize =  DEFAULT_PROGRESS_TEXT_SIZE;
            mProgressStrokeWidth =  DEFAULT_PROGRESS_STROKE_WIDTH;
            mProgressStartColor = new Color(COLOR_FFF2A670);
            mProgressEndColor = new Color(COLOR_FFF2A670);
            mProgressTextColor = new Color(COLOR_FFF2A670);
            mStartDegree = DEFAULT_START_DEGREE;
            mDrawBackgroundOutsideProgress =  false;
            mBlurRadius = 0;
            mBlurStyle = MaskFilter.Blur.NORMAL;
        }else {
            mProgressBackgroundColor = attrs.getAttr(AttrSetString.PROGRESS_BACKGROUND_COLOR).isPresent() ? attrs.getAttr(AttrSetString.PROGRESS_BACKGROUND_COLOR).get().getColorValue() : new Color(COLOR_FFD3D3D5);
            mLineCount = attrs.getAttr(AttrSetString.LINE_COUNT).isPresent() ? attrs.getAttr(AttrSetString.LINE_COUNT).get().getIntegerValue() : DEFAULT_LINE_COUNT;
            if (attrs.getAttr(AttrSetString.PROGRESS_STYLE).isPresent()) {
                mStyle = attrs.getAttr(AttrSetString.PROGRESS_STYLE).get().getStringValue().equals("line") ? LINE :
                        (attrs.getAttr(AttrSetString.PROGRESS_STYLE).get().getStringValue().equals("solid") ? SOLID :
                                (attrs.getAttr(AttrSetString.PROGRESS_STYLE).get().getStringValue().equals("solid_line") ? SOLID_LINE : LINE));
            } else {
                mStyle = LINE;
            }
            if (attrs.getAttr(AttrSetString.PROGRESS_SHADER).isPresent()) {
                mShader = attrs.getAttr(AttrSetString.PROGRESS_SHADER).get().getStringValue().equals("sweep") ? SWEEP :
                        (attrs.getAttr(AttrSetString.PROGRESS_SHADER).get().getStringValue().equals("radial") ? RADIAL :
                                (attrs.getAttr(AttrSetString.PROGRESS_SHADER).get().getStringValue().equals("linear") ? SOLID_LINE : LINEAR));
            } else {
                mShader = LINEAR;
            }

            mCap = attrs.getAttr(AttrSetString.PROGRESS_STROKE_CAP).isPresent() ?
                    (attrs.getAttr(AttrSetString.PROGRESS_STROKE_CAP).get().getStringValue().equals("round")
                            ? Paint.StrokeCap.ROUND_CAP : Paint.StrokeCap.BUTT_CAP)
                    : Paint.StrokeCap.BUTT_CAP;

            mLineWidth = attrs.getAttr(AttrSetString.LINE_WIDTH).isPresent() ? attrs.getAttr(AttrSetString.LINE_WIDTH).get().getIntegerValue() : vpToPx(getContext(), DEFAULT_LINE_WIDTH);
            mProgressTextSize = attrs.getAttr(AttrSetString.PROGRESS_TEXT_SIZE).isPresent() ? attrs.getAttr(AttrSetString.PROGRESS_TEXT_SIZE).get().getDimensionValue() : DEFAULT_PROGRESS_TEXT_SIZE;
            mProgressStrokeWidth = attrs.getAttr(AttrSetString.PROGRESS_STROKE_WIDTH).isPresent() ? attrs.getAttr(AttrSetString.PROGRESS_STROKE_WIDTH).get().getDimensionValue() : DEFAULT_PROGRESS_STROKE_WIDTH;

            mProgressStartColor = attrs.getAttr(AttrSetString.PROGRESS_START_COLOR).isPresent() ? attrs.getAttr(AttrSetString.PROGRESS_START_COLOR).get().getColorValue() : new Color(COLOR_FFF2A670);
            mProgressEndColor = attrs.getAttr(AttrSetString.PROGRESS_END_COLOR).isPresent() ? attrs.getAttr(AttrSetString.PROGRESS_END_COLOR).get().getColorValue() : new Color(COLOR_FFF2A670);
            mProgressTextColor = attrs.getAttr(AttrSetString.PROGRESS_TEXT_COLOR).isPresent() ? attrs.getAttr(AttrSetString.PROGRESS_TEXT_COLOR).get().getColorValue() : new Color(COLOR_FFF2A670);

            mStartDegree = attrs.getAttr(AttrSetString.PROGRESS_START_DEGREE).isPresent() ? attrs.getAttr(AttrSetString.PROGRESS_START_DEGREE).get().getIntegerValue() : DEFAULT_START_DEGREE;
            mDrawBackgroundOutsideProgress = attrs.getAttr(AttrSetString.DRAW_BACKGROUND_OUTSIDE_PROGRESS).isPresent() ? attrs.getAttr(AttrSetString.DRAW_BACKGROUND_OUTSIDE_PROGRESS).get().getBoolValue() : false;

            mBlurRadius = attrs.getAttr(AttrSetString.PROGRESS_BLUR_RADIUS).isPresent() ? attrs.getAttr(AttrSetString.PROGRESS_BLUR_RADIUS).get().getDimensionValue() : 0;
            String blurStyle = attrs.getAttr(AttrSetString.PROGRESS_BLUR_STYLE).isPresent() ? attrs.getAttr(AttrSetString.PROGRESS_BLUR_STYLE).get().getStringValue() : "";
            switch (blurStyle) {
                case "solid":
                    mBlurStyle = MaskFilter.Blur.SOLID;
                    break;
                case "outer":
                    mBlurStyle = MaskFilter.Blur.OUTER;
                    break;
                case "inner":
                    mBlurStyle = MaskFilter.Blur.INNER;
                    break;
                default:
                    mBlurStyle = MaskFilter.Blur.NORMAL;
                    break;
            }
        }
        addDrawTask(this);
        setLayoutRefreshedListener(this);
    }

    /**
     * Paint initialization
     */
    private void initPaint() {
        mProgressTextPaint.setTextAlign(TextAlignment.CENTER);
        mProgressTextPaint.setTextSize((int) mProgressTextSize);

        mProgressPaint.setStyle(mStyle == SOLID ? Paint.Style.FILL_STYLE : Paint.Style.STROKE_STYLE);
        mProgressPaint.setStrokeWidth(mProgressStrokeWidth);
        mProgressPaint.setColor(mProgressStartColor);
        mProgressPaint.setStrokeCap(mCap);
        updateMaskBlurFilter();

        mProgressBackgroundPaint.setStyle(mStyle == SOLID ?
                Paint.Style.FILL_STYLE : Paint.Style.STROKE_STYLE);
        mProgressBackgroundPaint.setStrokeWidth(mProgressStrokeWidth);
        mProgressBackgroundPaint.setColor(mProgressBackgroundColor);
        mProgressBackgroundPaint.setStrokeCap(mCap);
    }

    private void updateMaskBlurFilter() {
        if (mBlurStyle != null && mBlurRadius > 0) {
            mProgressPaint.setMaskFilter(new MaskFilter(mBlurRadius, mBlurStyle));
        } else {
            mProgressPaint.setMaskFilter(null);
        }
    }

    /**
     * The progress bar color gradient,
     * need to be invoked in the {#onSizeChanged(int, int, int, int)}
     */
    private void updateProgressShader() {
        if (mProgressStartColor != mProgressEndColor) {
            Shader shader = null;
            Paint.ShaderType shaderType = Paint.ShaderType.LINEAR_SHADER;
            switch (mShader) {
                case LINEAR: {
                    shader = new LinearShader(new Point[]{new Point(mProgressRectF.left, mProgressRectF.top)},
                            new float[]{mProgressRectF.left, mProgressRectF.bottom},
                            new Color[]{mProgressStartColor, mProgressStartColor},
                            Shader.TileMode.CLAMP_TILEMODE);
                    Matrix matrix = new Matrix();
                    matrix.setRotate(LINEAR_START_DEGREE, mCenterX, mCenterY);
                    shader.setShaderMatrix(matrix);
                    shaderType = Paint.ShaderType.LINEAR_SHADER;
                    break;
                }
                case RADIAL: {
                    shader = new RadialShader(new Point(mCenterX, mCenterY), mRadius, null,
                            new Color[]{mProgressStartColor, mProgressEndColor},
                            Shader.TileMode.CLAMP_TILEMODE);
                    shaderType = Paint.ShaderType.RADIAL_SHADER;
                    break;
                }
                case SWEEP: {
                    float radian = (float) (mProgressStrokeWidth / Math.PI * 2.0f / mRadius);
                    float rotateDegrees = (float) (
                            -(mCap == Paint.StrokeCap.BUTT_CAP && mStyle == SOLID_LINE ? 0 : Math.toDegrees(radian)));

                    shader = new SweepShader(mCenterX, mCenterY, new Color[]{mProgressStartColor, mProgressEndColor},
                            new float[]{0.0f, 1.0f});
                    Matrix matrix = new Matrix();
                    matrix.setRotate(rotateDegrees, mCenterX, mCenterY);
                    shader.setShaderMatrix(matrix);
                    shaderType = Paint.ShaderType.SWEEP_SHADER;
                    break;
                }
                default:
                    break;
            }

            mProgressPaint.setShader(shader, shaderType);
        } else {
            mProgressPaint.setShader(null, Paint.ShaderType.LINEAR_SHADER);
            mProgressPaint.setColor(mProgressStartColor);
        }
    }

    @Override
    public void onDraw(Component component, Canvas canvas) {
        if (!hasInitInfo) {
            initBoundInfo(component);
            updateProgressShader();
            hasInitInfo = true;
        }
        canvas.save();
        canvas.rotate(mStartDegree, mCenterX, mCenterY);
        drawProgress(canvas);
        canvas.restore();
        drawProgressText(canvas);
    }

    private void drawProgressText(Canvas canvas) {
        if (mProgressFormatter == null) {
            return;
        }

        CharSequence progressText = mProgressFormatter.format(mProgress, mMax);

        if (progressText == null || progressText.toString().length() == 0) {
            return;
        }

        mProgressTextPaint.setTextSize((int) mProgressTextSize);
        mProgressTextPaint.setColor(mProgressTextColor);

        mProgressTextRect = mProgressTextPaint.getTextBounds(String.valueOf(progressText));
        canvas.drawText(mProgressTextPaint, progressText.toString(), mCenterX, mCenterY + mProgressTextRect.getHeight() / 2);
    }

    private void drawProgress(Canvas canvas) {
        switch (mStyle) {
            case SOLID:
                drawSolidProgress(canvas);
                break;
            case SOLID_LINE:
                drawSolidLineProgress(canvas);
                break;
            case LINE:
            default:
                drawLineProgress(canvas);
                break;
        }
    }

    /**
     *  In the center of the drawing area as a reference point , rotate the canvas
     * @param canvas canvas
     */
    private void drawLineProgress(Canvas canvas) {
        float unitDegrees = (float) (2.0f * Math.PI / mLineCount);
        float outerCircleRadius = mRadius;
        float interCircleRadius = mRadius - mLineWidth;

        int progressLineCount = (int) ((float) mProgress / (float) mMax * mLineCount);

        for (int i = 0; i < mLineCount; i++) {
            float rotateDegrees = i * -unitDegrees;

            float startX = mCenterX + (float) Math.cos(rotateDegrees) * interCircleRadius;
            float startY = mCenterY - (float) Math.sin(rotateDegrees) * interCircleRadius;

            float stopX = mCenterX + (float) Math.cos(rotateDegrees) * outerCircleRadius;
            float stopY = mCenterY - (float) Math.sin(rotateDegrees) * outerCircleRadius;

            if (mDrawBackgroundOutsideProgress) {
                if (i >= progressLineCount) {
                    canvas.drawLine(new Point(startX, startY), new Point(stopX, stopY), mProgressBackgroundPaint);
                }
            } else {
                canvas.drawLine(new Point(startX, startY), new Point(stopX, stopY), mProgressBackgroundPaint);
            }

            if (i < progressLineCount) {
                canvas.drawLine(new Point(startX, startY), new Point(stopX, stopY), mProgressPaint);
            }
        }
    }

    /**
     * Just draw arc
     * @param canvas canvas
     */
    private void drawSolidProgress(Canvas canvas) {
        if (mDrawBackgroundOutsideProgress) {
            float startAngle = MAX_DEGREE * mProgress / mMax;
            float sweepAngle = MAX_DEGREE - startAngle;
            canvas.drawArc(mProgressRectF, new Arc(startAngle, sweepAngle, true), mProgressBackgroundPaint);
        } else {
            canvas.drawArc(mProgressRectF, new Arc(0.0f, MAX_DEGREE, true), mProgressBackgroundPaint);
        }
        canvas.drawArc(mProgressRectF, new Arc(0.0f, MAX_DEGREE * mProgress / mMax, true), mProgressPaint);
    }

    /**
     * Just draw arc
     * @param canvas canvas
     */
    private void drawSolidLineProgress(Canvas canvas) {
        if (mDrawBackgroundOutsideProgress) {
            float startAngle = MAX_DEGREE * mProgress / mMax;
            float sweepAngle = MAX_DEGREE - startAngle;
            Arc arc = new Arc(startAngle, sweepAngle, false);
            canvas.drawArc(mProgressRectF, arc, mProgressBackgroundPaint);
        } else {
            canvas.drawArc(mProgressRectF, new Arc(0.0f, MAX_DEGREE, false), mProgressBackgroundPaint);
        }
        Arc arc = new Arc(0.0f, MAX_DEGREE * mProgress / mMax, false);
        canvas.drawArc(mProgressRectF, arc, mProgressPaint);
    }

    /**
     * setProgressFormatter
     * @param progressFormatter progressFormatter
     */
    public void setProgressFormatter(ProgressFormatter progressFormatter) {
        mProgressFormatter = progressFormatter;
        invalidate();
    }

    /**
     * setProgressStrokeWidth
     * @param progressStrokeWidth progressStrokeWidth
     */
    public void setProgressStrokeWidth(float progressStrokeWidth) {
        mProgressStrokeWidth = progressStrokeWidth;
        matchRectF(mProgressRectF, mBoundsRectF);
        updateProgressShader();
        insetRect(mProgressRectF, mProgressStrokeWidth / 2, mProgressStrokeWidth / 2);
        invalidate();
    }

    /**
     * setProgressTextSize
     * @param progressTextSize progressTextSize
     */
    public void setProgressTextSize(float progressTextSize) {
        mProgressTextSize = progressTextSize;
        invalidate();
    }

    /**
     * setProgressStartColor
     * @param progressStartColor progressStartColor
     */
    public void setProgressStartColor(Color progressStartColor) {
        mProgressStartColor = progressStartColor;
        updateProgressShader();
        invalidate();
    }

    /**
     * setProgressEndColor
     * @param progressEndColor progressEndColor
     */
    public void setProgressEndColor(Color progressEndColor) {
        mProgressEndColor = progressEndColor;
        updateProgressShader();
        invalidate();
    }

    /**
     * setProgressTextColor
     * @param progressTextColor progressTextColor
     */
    public void setProgressTextColor(Color progressTextColor) {
        mProgressTextColor = progressTextColor;
        invalidate();
    }

    /**
     * setProgressBackgroundColor
     * @param progressBackgroundColor progressBackgroundColor
     */
    public void setProgressBackgroundColor(Color progressBackgroundColor) {
        mProgressBackgroundColor = progressBackgroundColor;
        mProgressBackgroundPaint.setColor(mProgressBackgroundColor);
        invalidate();
    }

    /**
     * setLineCount
     * @param lineCount lineCount
     */
    public void setLineCount(int lineCount) {
        mLineCount = lineCount;
        invalidate();
    }

    /**
     * setLineWidth
     * @param lineWidth lineWidth
     */
    public void setLineWidth(float lineWidth) {
        mLineWidth = lineWidth;
        invalidate();
    }

    /**
     * setStyle
     * @param style style
     */
    public void setStyle(@Style int style) {
        mStyle = style;
        mProgressPaint.setStyle(mStyle == SOLID ? Paint.Style.FILL_STYLE : Paint.Style.STROKE_STYLE);
        mProgressBackgroundPaint.setStyle(mStyle == SOLID ? Paint.Style.FILL_STYLE : Paint.Style.STROKE_STYLE);
        invalidate();
    }

    /**
     * setBlurRadius
     * @param blurRadius blurRadius
     */
    public void setBlurRadius(int blurRadius) {
        mBlurRadius = blurRadius;
        updateMaskBlurFilter();
        invalidate();
    }

    /**
     * setBlurStyle
     * @param blurStyle blurStyle
     */
    public void setBlurStyle(MaskFilter.Blur blurStyle) {
        mBlurStyle = blurStyle;
        updateMaskBlurFilter();
        invalidate();
    }

    /**
     * setShader
     * @param shader shader
     */
    public void setShader(@ShaderMode int shader) {
        mShader = shader;
        updateProgressShader();
        invalidate();
    }

    /**
     * setCap
     * @param cap cap
     */
    public void setCap(Paint.StrokeCap cap) {
        mCap = cap;
        mProgressPaint.setStrokeCap(cap);
        mProgressBackgroundPaint.setStrokeCap(cap);
        invalidate();
    }

    /**
     * setStartDegree
     * @param startDegree startDegree
     */
    public void setStartDegree(int startDegree) {
        mStartDegree = startDegree;
        invalidate();
    }

    /**
     * setDrawBackgroundOutsideProgress
     * @param drawBackgroundOutsideProgress drawBackgroundOutsideProgress
     */
    public void setDrawBackgroundOutsideProgress(boolean drawBackgroundOutsideProgress) {
        mDrawBackgroundOutsideProgress = drawBackgroundOutsideProgress;
        invalidate();
    }

    /**
     * 返回进度值
     * @return mProgress
     */
    public int getProgress() {
        return mProgress;
    }

    /**
     * setProgress
     * @param progress progress
     */
    public void setProgress(int progress) {
        mProgress = progress;
        invalidate();
    }

    /**
     * 获取最大进度值
     * @return mMax
     */
    public int getMax() {
        return mMax;
    }

    /**
     * setMax
     * @param max max
     */
    public void setMax(int max) {
        mMax = max;
        invalidate();
    }

    private void insetRect(RectFloat srcRectF, float dx, float dy) {
        if (srcRectF == null) {
            return;
        }
        srcRectF.left += dx;
        srcRectF.top += dy;
        srcRectF.right -= dx;
        srcRectF.bottom -= dy;
    }

    private void matchRect(Rect srcRectF, Rect targetRectF) {
        if (srcRectF == null || targetRectF == null) {
            return;
        }
        srcRectF.left = targetRectF.left;
        srcRectF.top = targetRectF.top;
        srcRectF.right = targetRectF.right;
        srcRectF.bottom = targetRectF.bottom;
    }

    private void matchRectF(RectFloat srcRectF, RectFloat targetRectF) {
        if (srcRectF == null || targetRectF == null) {
            return;
        }
        srcRectF.left = targetRectF.left;
        srcRectF.top = targetRectF.top;
        srcRectF.right = targetRectF.right;
        srcRectF.bottom = targetRectF.bottom;
    }

    /**
     * 是否初始化过一次后绘制 主要是因为onRefreshed在onDraw后执行，需要onDraw自己去初始化一次
     */
    private boolean hasInitInfo = false;

    @Override
    public void onRefreshed(Component component) {
        hasInitInfo = true;
        initBoundInfo(component);
        updateProgressShader();
    }

    private void initBoundInfo(Component component) {
        mBoundsRectF.left = getPaddingLeft();
        mBoundsRectF.top = getPaddingTop();
        mBoundsRectF.right = component.getWidth() - getPaddingRight();
        mBoundsRectF.bottom = component.getHeight() - getPaddingBottom();
        mCenterX = component.getWidth() / 2;
        mCenterY = component.getHeight() / 2;

        mRadius = Math.min(component.getWidth(), component.getHeight()) / 2;

        mProgressRectF.left = mBoundsRectF.left;
        mProgressRectF.top = mBoundsRectF.top;
        mProgressRectF.right = mBoundsRectF.right;
        mProgressRectF.bottom = mBoundsRectF.bottom;
    }

    @Retention(RetentionPolicy.SOURCE)
    private @interface Style {
    }

    @Retention(RetentionPolicy.SOURCE)
    private @interface ShaderMode {
    }

    /**
     * 文本定制ProgressFormatter
     */
    public interface ProgressFormatter {
        CharSequence format(int progress, int max);
    }

    /**
     * create DefaultProgressFormatter
     */
    public static final class DefaultProgressFormatter implements ProgressFormatter {
        private static final String DEFAULT_PATTERN = "%d%%";

        @Override
        public CharSequence format(int progress, int max) {
            return String.format(DEFAULT_PATTERN, (int) ((float) progress / (float) max * 100));
        }
    }

    /**
     * vp转px
     *
     * @param context 上下文
     * @param vp      vp
     * @return px
     */
    private static int vpToPx(Context context, float vp) {
        return (int) (context.getResourceManager().getDeviceCapability().screenDensity / 160 * vp);
    }
}